home *** CD-ROM | disk | FTP | other *** search
/ CDUTIL 13 / CDUTIL #13 Julio 1995.iso / windows / acadcom / ads / sample / dragger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  22.4 KB  |  718 lines

  1. /* Next available MSG number is  21 */
  2.  
  3. /***************************************************************************
  4.    Module Name:  dragger.c
  5.  
  6.    Copyright (C) 1992, 1993, 1994 by Autodesk, Inc.
  7.  
  8.    Permission to use, copy, modify, and distribute this software in 
  9.    object code form for any purpose and without fee is hereby granted, 
  10.    provided that the above copyright notice appears in all copies and 
  11.    that both that copyright notice and the limited warranty and 
  12.    restricted rights notice below appear in all supporting 
  13.    documentation.
  14.  
  15.    AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
  16.    AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
  17.    MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
  18.    DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
  19.    UNINTERRUPTED OR ERROR FREE.
  20.  
  21.    Use, duplication, or disclosure by the U.S. Government is subject to 
  22.    restrictions set forth in FAR 52.227-19 (Commercial Computer 
  23.    Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
  24.    (Rights in Technical Data and Computer Software), as applicable.
  25.     
  26.    .
  27.  
  28.    Description:Another Sample ADS application
  29.  
  30.    Author     : 
  31.                  Autodesk, Inc.
  32.                  2320 Marinship Way
  33.                  Sausalito, CA. 94965
  34.                  (415)332-2344
  35.  
  36.     Function Entry Points:
  37.         void
  38.         main(argc, argv)
  39.         int    argc;              [Number of argument passed in cmd line]
  40.         char   *argv[];           [Array of pointers to arguments]
  41.  
  42.     Exported ADS Functions
  43.         TESTDRAGGEN               [Test the ADS_DRAGGEN function]
  44.  
  45.     Modification History:
  46.         Feb 11 1992 - bcm - original creation
  47.  
  48.     Notes and restrictions on use:
  49.  
  50.  
  51. ***************************************************************************/
  52.  
  53. /**************************************************************************/
  54. /*  MODULE NAME  */
  55. /**************************************************************************/
  56. #define    DRAGGER
  57.  
  58. /****************************************************************************/
  59. /*  DEFINES  */
  60. /****************************************************************************/
  61. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  62.  
  63. /**************************************************************************/
  64. /*  TYPEDEFS  */
  65. /**************************************************************************/
  66. /* ADS Function Table */
  67. typedef struct {
  68.     char    *name;
  69.     int     (*fptr)();
  70. } ftblent;
  71.  
  72. typedef struct resbuf rbtype;
  73.  
  74. /**************************************************************************/
  75. /*  INCLUDES  */
  76. /**************************************************************************/
  77.  
  78. #include <stdio.h>
  79. #include <math.h>
  80. #ifndef __WATCOMC__
  81. #include <memory.h>
  82. #endif
  83. #include <string.h>
  84. #include "adslib.h"
  85. #include "ol_errno.h"
  86.  
  87. /****************************************************************************/
  88. /*  LOCAL FUNCTION FORWARD DECLARATIONS  */
  89. /****************************************************************************/
  90. int     testdraggen();
  91. int     dragsampler _((ads_point pt, ads_matrix mat));
  92.  
  93.  
  94. /**************************************************************************/
  95. /*  GLOBAL VARIABLES  */
  96. /**************************************************************************/
  97. /* Table of ADS functions */
  98. ftblent exfun[] = {
  99.             {/*MSG0*/"C:TESTDRAGGEN", testdraggen},
  100.         };
  101.  
  102. /* Table of keyword functions */
  103. char *kwtab[] = {
  104.                   /*MSG0*/"MXYZ",
  105.                   /*MSG0*/"SXYZ",
  106.                   /*MSG0*/"RX",
  107.                   /*MSG0*/"RY",
  108.                   /*MSG0*/"RZ",
  109.                   /*MSG0*/"NOP",
  110.                   /*MSG0*/"EXIT",
  111.                  };
  112.  
  113. #define MXYZ 0
  114. #define SXYZ 1
  115. #define RX   2
  116. #define RY   3
  117. #define RZ   4
  118. #define NOP  5
  119. #define EXIT 6
  120.  
  121. int       KwIndex = NOP;              /* Index into kwtab */
  122. ads_point Base;                       /* Base point for xform */
  123.  
  124. ads_matrix     CTM;                   /* Current Transformation Matrix */
  125. /**************************************************************************/
  126. /*  EXTERNAL FUNCTION DECLARATIONS  */
  127. /**************************************************************************/
  128.  
  129. /**************************************************************************/
  130. /*  EXTERNAL VARIABLE DECLARATIONS  */
  131. /**************************************************************************/
  132.  
  133. /****************************************************************************/
  134. /*  LOCAL FUNCTION DECLARATIONS  */
  135. /****************************************************************************/
  136. int funcload       _((void));
  137. int funcunload     _((void));
  138. int dofun          _((void));
  139. int geterrno       _((void));
  140. void ads_mat_ident _((ads_matrix matrix));
  141. void ads_subvec    _((ads_point ap, ads_point bp, ads_point dp));
  142. ads_real ads_fabsv _((ads_point ap));
  143. ads_real ads_dist  _((ads_point p1, ads_point p2));
  144. void ads_mat_rot   _((ads_real angle, int axis, ads_matrix m));
  145. void ads_mat_scale _((ads_real xscale, ads_real yscale, ads_real zscale,
  146.                       ads_matrix m));
  147. void ads_mat_x_vec _((ads_matrix mat, ads_point pin, ads_point pout));
  148. void ads_mat_x_pt  _((ads_matrix mat, ads_point pin, ads_point pout));
  149.  
  150. /******************************************************************************/
  151. /*.doc geterrno(internal) */
  152. /*+
  153.     This function is called to obtain the value of the AutoCAD system
  154.     variable ERRNO and return it as a result.
  155. -*/
  156. /******************************************************************************/
  157. int
  158. /*FCN*/geterrno()
  159. {
  160.     rbtype errval;
  161.  
  162.     ads_getvar(/*MSG0*/"ERRNO", &errval);
  163.  
  164.     return errval.resval.rint;
  165. }
  166.  
  167. /******************************************************************************/
  168. /*.doc funcload(internal) */
  169. /*+
  170.     This function is called to define all function names in the ADS
  171.     function table.  Each named function will be callable from lisp or
  172.     invokable from another ADS application.
  173. -*/
  174. /******************************************************************************/
  175. int
  176. /*FCN*/funcload()
  177. {
  178.     int i;
  179.  
  180.     for (i = 0; i < ELEMENTS(exfun); i++) {
  181.         if (!ads_defun(exfun[i].name, i))
  182.             return RTERROR;
  183.     }
  184.  
  185.     return RTNORM;
  186. }
  187.  
  188. /******************************************************************************/
  189. /*.doc funclunoad(internal) */
  190. /*+
  191.     This function is called to undefine all function names in the ADS
  192.     function table.  Each named function will be removed from the
  193.     AutoLISP hash table.
  194. -*/
  195. /******************************************************************************/
  196. int
  197. /*FCN*/funcunload()
  198. {
  199.     int i;
  200.  
  201.     /* Undefine each function we defined */
  202.  
  203.     for (i = 0; i < ELEMENTS(exfun); i++) {
  204.         ads_undef(exfun[i].name,i);
  205.     }
  206.  
  207.     return RTNORM;
  208. }
  209. /******************************************************************************/
  210. /*.doc dofun(internal) */
  211. /*+
  212.     This function is called to invoke the function which has the
  213.     registerd function code that is obtained from  ads_getfuncode.  The
  214.     function will return RTERROR if the function code is invalid, or
  215.     RSERR if the invoked function fails to return RTNORM.  The value
  216.     RSRSLT will be returned if the function code is valid and the
  217.     invoked subroutine returns RTNORM.
  218. -*/
  219. /******************************************************************************/
  220. int
  221. /*FCN*/dofun()
  222. {
  223.     int val;
  224.  
  225.     if ((val = ads_getfuncode()) < 0 || val > ELEMENTS(exfun))
  226.         return RTERROR;
  227.  
  228.     return ((*exfun[val].fptr)() == RTNORM ? RSRSLT:RSERR);
  229. }
  230.  
  231. /******************************************************************************/
  232. /*.doc main(internal) */
  233. /*+
  234.     This is the main entry point for the ADS application.  All ADS
  235.     requests will be dispatched from this function.  This is your
  236.     standard ADS dispatch loop.
  237. -*/
  238. /******************************************************************************/
  239. void
  240. /*FCN*/main(argc,argv)
  241. int argc;
  242. char *argv[];
  243. {
  244.     short scode = RSRSLT;          /* Normal result code (default) */
  245.     int   stat;
  246.     char errmsg[80];
  247.  
  248.     ads_init(argc, argv);          /* Initiate communication with AutoLISP */
  249.  
  250.     for ( ;; ) {                   /* Request/Result loop */
  251.  
  252.         if ((stat = ads_link(scode)) < 0) {
  253.             sprintf(errmsg,
  254.                     /*MSG1*/"DRAGGER: bad status from ads_link() = %d\n",
  255.                     stat);
  256. #ifdef Macintosh
  257.             macalert(errmsg);
  258. #else
  259.             puts(errmsg);
  260.             fflush(stdout);
  261. #endif /* Macintosh */
  262.             exit(1);
  263.         }
  264.  
  265.         scode = RSRSLT;           /* Reset result code */
  266.  
  267.         switch (stat) {
  268.  
  269.         case RQXLOAD:             /* Load & define functions */
  270.             scode = funcload() ? -RSRSLT : -RSERR;
  271.             break;
  272.  
  273.         case RQXUNLD:             /* Unload functions */
  274.             scode = funcunload() ? -RSRSLT : -RSERR;
  275.             ads_printf(/*MSG2*/"Unloading.\n");
  276.             break;
  277.  
  278.         case RQSUBR:             /* Handle request for external function */
  279.             dofun();
  280.             break;
  281.  
  282.         default:
  283.             break;
  284.         }
  285.     }
  286. }
  287.  
  288. /******************************************************************************/
  289. /*.doc ads_mat_ident(internal) */
  290. /*+
  291.     Set up an identity matrix.
  292. -*/
  293. /******************************************************************************/
  294. void
  295. /*FCN*/ads_mat_ident(matrix)
  296. ads_matrix matrix;
  297. {
  298.     extern ads_matrix ads_identmat;
  299.     memcpy(matrix, ads_identmat, sizeof(ads_matrix));
  300. }
  301.  
  302. /******************************************************************************/
  303. /*.doc ads_subvec(internal) */
  304. /*+
  305.     Subtract two ads_points.
  306. -*/
  307. /******************************************************************************/
  308. void
  309. /*FCN*/ads_subvec(ap, bp, dp)
  310. ads_point ap, bp;
  311. ads_point dp;
  312. {
  313.     dp[X] = ap[X] - bp[X];
  314.     dp[Y] = ap[Y] - bp[Y];
  315.     dp[Z] = ap[Z] - bp[Z];
  316. }
  317.  
  318.  
  319. /******************************************************************************/
  320. /*.doc ads_fabsv(internal) */
  321. /*+
  322.     Get normal of a vector.
  323. -*/
  324. /******************************************************************************/
  325. ads_real
  326. /*FCN*/ads_fabsv(ap)
  327. ads_point ap;
  328. {
  329.     return sqrt(ap[X] * ap[X] + ap[Y] * ap[Y] + ap[Z] * ap[Z]);
  330. }
  331.  
  332. /******************************************************************************/
  333. /*.doc ads_dist(internal) */
  334. /*+
  335.     Calculate distance between two points.
  336. -*/
  337. /******************************************************************************/
  338. ads_real
  339. /*FCN*/ads_dist(p1, p2)
  340. ads_point p1, p2;
  341. {
  342.     ads_point pd;
  343.  
  344.     ads_subvec(p1, p2, pd);
  345.     return ads_fabsv(pd);
  346. }
  347.  
  348.  
  349. /******************************************************************************/
  350. /*.doc ads_mat_ixlate(internal) */
  351. /*+
  352.     Set up a translation matrix.
  353. -*/
  354. /******************************************************************************/
  355. void
  356. /*FCN*/ads_mat_ixlate(vec, result)
  357. ads_point vec;
  358. ads_matrix   result;
  359. {
  360.     ads_mat_ident(result);
  361.     result[X][T] = - vec[X];
  362.     result[Y][T] = - vec[Y];
  363.     result[Z][T] = - vec[Z];
  364. }
  365.  
  366. /******************************************************************************/
  367. /*.doc ads_mat_rot(internal) */
  368. /*+
  369.     Generate a matrix that rotates about a given axis.
  370. -*/
  371. /******************************************************************************/
  372. void
  373. /*FCN*/ads_mat_rot(angle, axis, m)
  374. ads_real angle;
  375. int axis;
  376. ads_matrix m;
  377. {
  378.     int axp1, axp2;
  379.  
  380.     axp1 = (axis + 1) % 3;
  381.     axp2 = (axis + 2) % 3;
  382.     ads_mat_ident(m);
  383.     m[axp1][axp1] = m[axp2][axp2] = cos(angle);
  384.     m[axp1][axp2] = -(m[axp2][axp1] = sin(angle));
  385. }
  386.  
  387. /******************************************************************************/
  388. /*.doc ads_mat_scale(internal) */
  389. /*+
  390.     Generate a matrix that scales the 3 axes by given amounts.
  391. -*/
  392. /******************************************************************************/
  393. void
  394. /*FCN*/ads_mat_scale(xscale, yscale, zscale, m)
  395. ads_real xscale, yscale, zscale;
  396. ads_matrix m;
  397. {
  398.     ads_mat_ident(m);
  399.     m[X][X] = xscale;
  400.     m[Y][Y] = yscale;
  401.     m[Z][Z] = zscale;
  402. }
  403.  
  404. /******************************************************************************/
  405. /*.doc ads_mat_x_pt(internal) */
  406. /*+
  407.     Multiply matrix by a given point.  Note that it does translation.
  408. -*/
  409. /******************************************************************************/
  410. void
  411. /*FCN*/ads_mat_x_pt(mat, pin, pout)
  412. ads_matrix mat;
  413. ads_point pin;
  414. ads_point pout;
  415. {
  416.     int i;
  417.     ads_point temp;
  418.  
  419.     for (i = X; i <= Z; i++)
  420.         temp[i] = mat[i][X] * pin[X] +
  421.                   mat[i][Y] * pin[Y] +
  422.                   mat[i][Z] * pin[Z] +
  423.                   mat[i][T];
  424.     memcpy(pout, temp, sizeof(ads_point));
  425. }
  426.  
  427. /******************************************************************************/
  428. /*.doc ads_mat_x_vec(internal) */
  429. /*+
  430.     Multiply matrix by a given vector.  Note that it does NO translation.
  431. -*/
  432. /******************************************************************************/
  433. void
  434. /*FCN*/ads_mat_x_vec(mat, pin, pout)
  435. ads_matrix mat;
  436. ads_point pin;
  437. ads_point pout;
  438. {
  439.     int i;
  440.     ads_point temp;
  441.  
  442.     for (i = X; i <= Z; i++)
  443.         temp[i] = mat[i][X] * pin[X] +
  444.                   mat[i][Y] * pin[Y] +
  445.                   mat[i][Z] * pin[Z];
  446.     memcpy(pout, temp, sizeof(ads_point));
  447. }
  448.  
  449. /******************************************************************************/
  450. /*.doc ads_mat_x_mat(internal) */
  451. /*+
  452.     Multiply two matrices.  Any or all arguments may point to the same array.
  453. -*/
  454. /******************************************************************************/
  455. void
  456. /*FCN*/ads_mat_x_mat(mata, matb, matout)
  457. ads_matrix mata;
  458. ads_matrix matb;
  459. ads_matrix matout;
  460. {
  461.     ads_matrix t;
  462.     int i, j, k;
  463.     ads_real sum;
  464.  
  465.     for (i = 0; i < 4; i++)
  466.         for (j = 0; j < 4; j++) {
  467.             sum = 0.0;
  468.             for (k=0; k<4; k++)
  469.                 sum += mata[i][k] * matb[k][j];
  470.             t[i][j] = sum;
  471.         }   
  472.     memcpy(matout, t, sizeof(ads_matrix));
  473. }
  474.  
  475.   
  476. /******************************************************************************/
  477. /*.doc dragsampler(internal) */
  478. /*+
  479.     ADS_DRAGGEN sampler function.  This function is called every time the
  480.     digitizer is moved.  It receives two arguments, the first is pt, and
  481.     the second is mat.  The argument pt is the current digitizer location,
  482.     and the arguemnt mat is the transformation matrix which is being used
  483.     by AutoCAD to display the current selection set of objects.
  484.  
  485.     The global KwIndex is an integer variable which contains a code
  486.     representing the current drag mode.  The possible values are MXYZ,
  487.     SXYZ, RX, RY, RZ, NOP, and EXIT.  This variable is set in the function
  488.     testdraggen.
  489.  
  490.     The global CTM is set to the value of the argument mat before
  491.     returning from the dragsampler.  This variable is used by testdraggen
  492.     when performing an ADS_XFORSS call.
  493. -*/
  494. /******************************************************************************/
  495. int
  496. /*FCN*/dragsampler(pt, mat)
  497. ads_point    pt;
  498. ads_matrix        mat;
  499. {
  500.  
  501.     ads_real        D;
  502.     ads_real        angle;
  503.     ads_point       tp;
  504.     int             axis;
  505.  
  506.     switch(KwIndex) {
  507.     case MXYZ:
  508.         /* generate translation matrix */
  509.         ads_subvec(pt, Base, tp);
  510.         ads_mat_x_vec(mat, tp, tp);
  511.         mat[X][T] = tp[X];
  512.         mat[Y][T] = tp[Y];
  513.         mat[Z][T] = tp[Z];
  514.  
  515.         break;
  516.  
  517.     case SXYZ:
  518.         /* generate uniformly scaled matrix */
  519.         D = ads_dist(pt, Base);
  520.         if (D < .0001)
  521.             D = .0001;
  522.         ads_mat_scale(D,D, D, mat);
  523.  
  524.         /* calculate new translation point */
  525.         ads_mat_x_vec(mat, Base, tp);
  526.         ads_subvec(Base, tp, tp);
  527.         mat[X][T] = tp[X];
  528.         mat[Y][T] = tp[Y];
  529.         mat[Z][T] = tp[Z];
  530.  
  531.         break;
  532.  
  533.     case RX:
  534.     case RY:
  535.     case RZ:
  536.         switch (KwIndex) {
  537.         case RX:
  538.             axis = X;
  539.             break;
  540.         case RY:
  541.             axis = Y;
  542.             break;
  543.         case RZ:
  544.             axis = Z;
  545.             break;
  546.         }
  547.  
  548.  
  549.         /* calculate angle of line between LastPoint and tp */
  550.         ads_subvec(pt, Base, tp);
  551.         angle = ads_angle(Base, pt);
  552.  
  553.         /* generate rotation matrix about axis */
  554.         ads_mat_rot(angle, axis, mat);
  555.  
  556.         /* calculate new translation point */
  557.         ads_mat_x_vec(mat, Base, tp);
  558.         ads_subvec(Base, tp, tp);
  559.         mat[X][T] = tp[X];
  560.         mat[Y][T] = tp[Y];
  561.         mat[Z][T] = tp[Z];
  562.  
  563.         break;
  564.     case EXIT:
  565.         return RTCAN;
  566.     case NOP:
  567.     default:
  568.         return RTNONE;
  569.     }
  570.  
  571.     memcpy(CTM, mat, sizeof(ads_matrix));
  572.     return RTNORM;
  573. }
  574.  
  575. /******************************************************************************/
  576. /*.doc testdraggen(internal) */
  577. /*+
  578.     This function is called from dofun as a result of an RQSUBR
  579.     request being sent to the main dispatch loop.
  580.  
  581.     It instructs the user to select the set of entitis that will be
  582.     dragged by the ads_draggen function.  The selection is obtained by
  583.     performing an ads_ssget Crossing.  If a selection set contains one
  584.     or more entities, then the user will be instructed to move the
  585.     mouse for dragging the object(s), or enter a keyword to modify the
  586.     behavior of the dragging operation.
  587.  
  588.     The list of keywords is obtained from the keytable, and each
  589.     keyword in the table has a different affect on the sampler function.
  590.     The sampler will perform the transformation indicated by the value of
  591.     KwIndex.
  592.  
  593.     Once a valid point has been selected, this test function will
  594.     attempt to transform the selection set of entities in the database.
  595.     The transformation will not work if the transformation matrix
  596.     contains a non uniform scale.
  597.  
  598.     The return value for this function is the last value in rc.
  599. -*/
  600. /******************************************************************************/
  601. int
  602. /*FCN*/testdraggen()
  603. {
  604.     int         x;
  605.     int         rc;
  606.     long        slen;
  607.     ads_point   pt1;
  608.     ads_point   pt2;
  609.     ads_point   pt3;
  610.     ads_name    ssname;
  611.     rbtype      *args;
  612.     char        tstr[512];
  613.     char        kwlist[128];
  614.     char        draggenprompt[512];
  615.     int         cur;
  616.  
  617.     args = ads_getargs();
  618.     ads_mat_ident(CTM);
  619.     cur = 0;
  620.     /* Build the key word list from the key word table */
  621.     kwlist[0] = '\0';
  622.     for (x = 0; x < ELEMENTS(kwtab); x++) {
  623.         if (x != 0)
  624.             strcat(kwlist, /*MSG0*/" ");
  625.         strcat(kwlist, kwtab[x]);
  626.     }
  627.  
  628.     /* Select entities for DRAGGEN test */
  629.     ads_printf(/*MSG3*/"\nPerforming ads_draggen test\n");
  630.     if (args != NULL) {
  631.         ads_printf(/*MSG4*/"I don't need any arguments from you.\n");
  632.         ads_retlist(args);
  633.     }
  634.     KwIndex = NOP;
  635.     ads_printf(/*MSG5*/"Select entities to be dragged\n");
  636.     if (ads_getpoint(NULL, /*MSG6*/"\nSelect first corner:", pt1) == RTNORM) {
  637.         if (ads_getcorner(pt1, /*MSG7*/"\nSelect other corner:", pt2) == RTNORM) {
  638.             ads_ssget(/*MSG0*/"_C", pt1, pt2, NULL, ssname);
  639.             rc = ads_sslength(ssname, &slen);
  640.             if (rc != RTNORM || slen == 0L)
  641.                 return RTNORM;
  642.             ads_getpoint(NULL, /*MSG8*/"\nSelect base point", Base);
  643.             sprintf(draggenprompt, /*MSG9*/"\nMove mouse or enter :(%s)", kwlist);
  644.             do {
  645.                 ads_initget(RSG_NONULL|RSG_OTHER, kwlist);
  646.                 rc = ads_draggen(ssname,
  647.                                  draggenprompt,
  648.                                  cur,
  649.                                  dragsampler,
  650.                                  pt3);
  651.                 switch (rc) {
  652.                 case RTKWORD:
  653.                     ads_getinput(tstr);
  654.                     rc = RTNORM;
  655.                     for (x = 0; x < ELEMENTS(kwtab); x++) {
  656.                         if (strcmp(tstr, kwtab[x]) == 0) {
  657.                             KwIndex = x;
  658.                             ads_mat_ident(CTM);
  659.                             break;
  660.                         }
  661.                     }
  662.                     if (x >= ELEMENTS(kwtab))
  663.                         ads_printf(/*MSG10*/"\n%s is invalid keyword.", tstr);
  664.                     break;
  665.                 case RTSTR:
  666.                     ads_getinput(tstr);
  667.                     rc = RTNORM;
  668.                     ads_printf(/*MSG11*/"You entered :%s\n", tstr);
  669.                     break;
  670.                 case RTNORM:
  671.                     rc = ads_xformss(ssname, CTM);
  672.                     if (rc != RTNORM)
  673.                         switch(geterrno()) {
  674.                         case OL_ESSVALID:
  675.                             ads_printf(/*MSG12*/"\nInvalid selection set.\n");
  676.                             break;
  677.                         case OL_EDELENT:
  678.                             ads_printf(/*MSG13*/"\nSelection set contains deleted entity.\n");
  679.                             break;
  680.                         case OL_EMODSEQ:
  681.                             ads_printf(/*MSG14*/"\nCan't xform a SEQEND entity.\n");
  682.                             break;
  683.                         case OL_ERGBUSY:
  684.                             ads_printf(/*MSG15*/"\nComplex regen in progress.\n");
  685.                             break;
  686.                         case OL_EMMVPORT:
  687.                             ads_printf(/*MSG16*/"\nCan't xform vport entity.\n");
  688.                             break;
  689.                         case OL_EMMLL:
  690.                             ads_printf(/*MSG17*/"\nCan't xform entity on locked layer.\n");
  691.                             break;
  692.                         case OL_EXFMVALID:
  693.                             ads_printf(/*MSG18*/"\nInvalid transformation matrix.\n");
  694.                             break;
  695.                         }
  696.  
  697.                     ads_mat_x_pt(CTM, Base, Base);
  698.                     ads_mat_ident(CTM);
  699.                     break;
  700.                 case RTCAN:
  701.                     ads_printf(/*MSG19*/"\nThe drag was aborted\n");
  702.                     break;
  703.                 case RTERROR:
  704.                 default:
  705.                     ads_printf(/*MSG20*/"\nDrag operation failed\n");
  706.                     break;
  707.                 }
  708.             } while (rc == RTNORM);
  709.             /* release the selection set */
  710.             ads_ssfree(ssname);
  711.         }
  712.     }
  713.  
  714.  
  715.     return RTNORM;
  716. }
  717.  
  718.